/*!： https://learnku.com/docs/async-book/2018/why_async/4787
为什么要异步
因为异步代码能让我们在同一个系统线程上并发执行多项任务。在一个典型的多线程应用里，如果你想同时下载两个不同的网页，
 你必须将这两项工作分配到两个不同的线程上，像这样：
 fn get_two_sites() {
     // 创建两个线程分别执行各自的下载任务
     let thread_one = thread::spawn(|| download("https:://www.foo.com"));
     let thread_two = thread::spawn(|| download("https:://www.bar.com"));
      // 等待两个线程完成任务
     thread_one.join();
     thread_two.join();
 }

对很多应用来说这就足够了 —— 这样一来，多线程就被设计为只用来一次性执行多个不同任务。但这也带来了一些限制。
 在线程切换和跨线程共享数据上会产生很多额外开销。即使是一个什么都不做的线程也会用尽珍贵的系统资源，
 而这就是异步代码要减少的开销。我们可以使用 Rust 的 async/await! 重写上面的函数，实现执行多个任务的目标而不用创建多个线程：
 async fn get_two_sites() {
     // Create a two different "futures" which, when run to completion,
     // will asynchronously download the webpages.
     // 创建两个不同的 future，当它们被完成执行时会异步下载不同的网页
    let future_one = download_async("https:://www.foo.com");
     let future_two = download_async("https:://www.bar.com");
      // 同时执行两个 future 使它们完成
     join!(future_one, future_two);
 }
 总之，相比多线程实现来说，异步实现的应用具有使用更少的资源获得更高性能的潜力。线程由操作系统支持，
 使用它们并不需要特别的编程模型 —— 任何函数都可以创建一个线程，而调用一个使用多线程的函数就像调用一个普通函数一样简单。
 但是异步函数就需要语言层面或者类库层面提供特殊的支持才能工作。在 Rust 中，async fn 会创建一个异步函数，当
 它被调用时，会返回一个需要依次执行函数体来完成的 future 对象。
 传统多线程应用也可以非常有效，Rust 的较小的内存占用以及可预测性意味着你可以做更多的事，即使不使用 async 关键字。
 然而，异步编程模型增长的复杂性并不总是值得的，想清楚你的应用采用简单多线程模型是否会更好仍然是很重要的。

 入门
 async/.await 是 Rust 语言用于编写像同步代码一样的异步函数的内置工具。async 将一个代码块转化为一个实现了名为
 Future 的特质（trait）的状态机。虽然在同步方法中调用阻塞函数会阻塞整个线程，但阻塞的 Futures
 将让出线程控制权，允许其他 Futures 运行。
 要创建异步函数，可以使用 async fn 语法：

!*/
use std::{time::Duration, thread};

use futures::executor::block_on;
mod future;
mod tokio;
mod time_future;
mod pin;

///async fn 返回的值是一个 Future，需要在执行者上运行才能起作用:
async fn do_something() {
    println!("hello, world!");
}

#[test]
pub fn hell_async(){
    let future = do_something();
    //通过block_on调用
    block_on(future);
}

struct Song{
    name: String,
}

///学唱歌
async fn learn_song() -> Song{
    println!("learn song!");

    //thread::sleep(Duration::from_secs(10));//标准库中的线程阻塞,阻塞的是系统级线程，对future达不到异步效果。
    println!("learn song done");
    Song {
        name: String::from("new song"),
    }
}
///唱歌
async fn sing_song(song: Song) {
    println!("sing song");
}
///跳舞
async fn dance(id: i32) {
    println!("dance {}!", id)
}

///先学唱歌，再唱歌，但学唱歌和唱歌的同时可以跳舞。

async fn learn_and_sing(){
    // 在唱歌之前等待学歌完成
    let learn_future = learn_song();
    // 这里我们使用 `.await` 运行future任务直到完成  .await只能在async中
    let song = learn_future.await;
    sing_song(song).await;
    
}

async fn sing_or_dance(){
    let f1 = learn_and_sing();
    let f2 = dance(1);
  
    // `join!` 类似于 `.await` ，但是可以等待多个 future 并发完成
    // 如果学歌的时候有了短暂的阻塞，跳舞将会接管当前的线程，如果跳舞变成了阻塞
    // 学歌将会返回来接管线程。如果两个futures都是阻塞的，

    futures::join!(f1, f2 );
}


#[test]
pub fn await_demo(){
    let f = sing_or_dance();
    block_on(f);
}